#include "byte_stream.hh"

#include <cstring>

// Dummy implementation of a flow-controlled in-memory byte stream.

// For Lab 0, please replace with a real implementation that passes the
// automated checks run by `make check_lab0`.

// You will need to add private members to the class declaration in `byte_stream.hh`

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

ByteStream::ByteStream(const size_t capacity_) {
    this->capacity = capacity_;
    buf = static_cast<char *>(malloc(this->capacity + 10));
    nwrite = 0;
    nread = 0;
}

size_t ByteStream::write(const string &data) {
    if (input_ended()) {
        return 0;
    }
    // printf("ByteStream write cap: %zu, nwrite: %zu, nread: %zu\n", capacity, nwrite, nread);
    for (size_t i = 0; i < data.length(); ++i) {
        if (remaining_capacity() > 0) {
            buf[nwrite % capacity] = data[i];
            nwrite++;
        } else {
            return i;
        }
    }
    // printf("now new write: %ld\n\n", data.length());
    return data.length();
}

//! \param[in] len bytes will be copied from the output side of the buffer
string ByteStream::peek_output(const size_t len) const {
    string s;
    for (size_t i = 0; i < len; ++i) {
        size_t idx = (nread + i) % capacity;
        if (nread + i < nwrite) {
            s += buf[idx];
        } else {
            break;
        }
    }
    return s;
}

//! \param[in] len bytes will be removed from the output side of the buffer
void ByteStream::pop_output(const size_t len) {
    for (size_t i = 0; i < len; ++i) {
        if (nread < nwrite) {
            nread++;
        } else {
            break;
        }
    }
}

//! Read (i.e., copy and then pop) the next "len" bytes of the stream
//! \param[in] len bytes will be popped and returned
//! \returns a string
std::string ByteStream::read(const size_t len) {
    string s = peek_output(len);
    pop_output(len);
    return s;
}

void ByteStream::end_input() { writeopen = false; }

bool ByteStream::input_ended() const { return !writeopen; }

size_t ByteStream::buffer_size() const { return nwrite - nread; }

bool ByteStream::buffer_empty() const { return buffer_size() == 0; }

//
// 原来eof是这个意思....
// 写管道已经关闭，且已经读完管道中所有的数据。
// 即没有剩余的字符串留在缓冲区里。
//
bool ByteStream::eof() const { return (nwrite == nread && input_ended()); }

size_t ByteStream::bytes_written() const { return nwrite; }

size_t ByteStream::bytes_read() const { return nread; }

size_t ByteStream::remaining_capacity() const { return capacity - buffer_size(); }